#pragma once

#include <iostream>
#include<string>
#include<cstring>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<unistd.h>
#include<signal.h>
#include<json/json.h>//如果在usr/include目录下面是可以访问的的！但是它有一个二级目录归类，所以要是json/json.h

#define SEP " "
#define SEP_LEN strlen(SEP) //不能使用sizeof！因为sizeof会把\0一起计入！
#define LINE_SEP "\r\n"
#define LINE_SEP_LEN strlen(LINE_SEP)




////////////////////////////////////////协议定制部分/////////////////////////////////////////////////
enum{OK = 0,DIV_ZERO,MOD_ZERO,OP_ERR};
std::string enLength(const std::string& text)
{
    //处理给我们的字符串在前面加上固定大小的信息！
    //exitcode reslut ——> content_len\r\nexitcode reslut\r\n
    //x op y ——> content_len\r\x op y\r\n
    //将其变成这样这样子！
    std::string send_string = std::to_string(text.size());//获取context_len
    send_string += LINE_SEP;// 加上\r\n
    send_string += text;
    send_string += LINE_SEP; // 加上\r\n

    return send_string;
}

bool deLength(const std::string& package,std::string * text)
{
    //这个接口用于分离报文前的固定字段！
    //如何保证我们能够将前面的长度读取完呢？——读取到\r\n即可！
    auto pos = package.find(LINE_SEP);
    if(pos == std::string::npos) return false;

    std::string text_len_string = package.substr(0,pos);
    int text_len = stoi(text_len_string);
    std::string text_constent = package.substr(pos+LINE_SEP_LEN,text_len);
    if(text_constent.empty()) return false;
    *text = text_constent;

    return true;
}

////////////////////////////////////////协议定制部分/////////////////////////////////////////////////

///协议定制和序列化与反序列化是不同的部分！//


////////////////////////////////////////序列化和反序列化部分！/////////////////////////////////////////////////

class Request//请求——这就是协议
{
public:
    Request():x_(0),y_(0),op_(0)
    {}
    Request(int x,int y,int op):x_(x),y_(y),op_(op)
    {}
    //request类自己的序列化和反序列化接口！
    bool Serialize(std::string* out)
    {

#ifdef MYSELF
        *out = "";//清空
        //"结构化——>" "x op y\r\n"中间只有一个空格！\r\n是为了方便调试！也是作为每一个报文的分隔符！
        std::string x_string = std::to_string(x_);
        std::string y_string = std::to_string(y_);
        if(y_string.empty() || x_string.empty()) return false;
       *out = x_string + SEP + op_ + SEP + y_string + LINE_SEP;

#else

        Json::Value root;//这是一个万能对象！可以用来接收任何对象！
        root["first"]  = x_;//json是一个kv结构！x是一个整数！但是传入后会自动的转换为字符串！
        root["second"] = y_;
        root["oper"] = op_;

        Json::FastWriter writer;
        // Json::StyledWriter writer;//这两种是json字符串结构化形成的两种风格！

        *out = writer.write(root);//然后将我们结构化的数据传入就会自动的进行序列化了！
        //该函数的返回值一个string！然后我们就可以获得一个序列化了
#endif
       return true;
    }



    bool Deserialize(const std::string& in)
    {

#ifdef MYSELF
        //以空格作为分隔符，将x，y，op都提取出来！"x op y" ——> 结构化数据
        //进行字串截取！
        auto left = in.find(SEP);//第一个分隔符
        auto right = in.rfind(SEP);//第二个分隔符！
        if(left == std::string::npos || right == std::string::npos)
        {
            return false;
        }
        if(left == right)
        {
            return false;
        }
        std::string x_string = in.substr(0,left);//[start,end) 长度就是end - start！
        std::string y_string = in.substr(right+SEP_LEN);

        // 123 + 12312 
        // if(right - (left+SEP_LEN) == 1)
        // {
        //     return false;
        // }
        // char op = in.substr(left + SEP_LEN, right - (left + SEP_LEN))[0];
        if(x_string.empty() || y_string.empty())
        {
            return false;
        }
        char op = in[left+SEP_LEN];

        x_ = std::stoi(x_string);
        y_ = std::stoi(y_string);
        op_ =op;

#else
        //反序列化就是根据key提取value!        
        Json::Value root;
        Json::Reader reader;
        reader.parse(in,root);
        //parse第一个参数就是从那个流里面进行反序列化！
        //然后将其放进哪里！
        x_ = root["first"].asInt();//因为json的所有的值都是默认是字符串的所以我们可以使用asInt转化为整形！
        y_ = root["second"].asInt();

        op_ = root["oper"].asInt();//因为op是一个char类型本来就是一个整数，所以这里我们也按照整数来读取！
        //这就完成了反序列化！


#endif
        return true;
    }



public:
    // "x op y"
    int x_;
    int y_;
    char op_;
    //约定我们的请求包含三个字段！x，y是第一，第二个数字，op是操作符！
};


class Respone//响应——这就是协议
{
public:

    Respone():result_(0),exitcode_(0)
    {}

    Respone(int exitcode,int result):result_(result),exitcode_(exitcode)
    {}
    //response类的序列化和反序列和接口！
    bool Serialize(std::string* out)
    {
#ifdef MYSELF
        *out = "";
        std::string ec_string = std::to_string(exitcode_);
        std::string res_string = std::to_string(result_);

        *out = ec_string;
        *out +=SEP;
        *out += res_string;

#else
        Json::Value root;
        root["exitcode"] = exitcode_;
        root["result"] = result_;

        Json::FastWriter writer;
        *out = writer.write(root);

        //这就完成了反序列化！

#endif
        return true;
    }

    bool Deserialize(const std::string& in)
    {

#ifdef MYSELF
        //"exitcode result"
        auto pos = in.find(SEP);
        if(pos == std::string::npos)
        {
            return false;
        }
        std::string ec_string = in.substr(0,pos);
        std::string re_string = in.substr(pos+SEP_LEN);

        if(ec_string.empty() || re_string.empty())
        {
            return false;
        }
        exitcode_ = std::stoi(ec_string);
        result_ = std::stoi(re_string);
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in,root);

        exitcode_ = root["exitcode"].asInt();
        result_ = root["result"].asInt();


#endif
        return true;
    }
public:
//我们约定
    int exitcode_;//0 表示计算成功！ 非0表示计算失败！具体是多少,可以定好标准！例如：1可以表示除2可以表示符号错误等等
    int result_;//计算结果！！
};
////////////////////////////////////////序列化和反序列化部分！/////////////////////////////////////////////////

bool recvPackage(int sock, std::string inbuffer, std::string *text)
{
    // static std::string inbuffer;//延长生命周期！
    // //加上static的原因是万一我们一次性读取到了很多的请求！
    // //但是我们只拿走一个请求！如果不加上static那么这些请求不就随着作用域一起被销毁了吗？
    // //但是我们加上static后哪怕出了作用域，这些请求依旧会被保存！

    char buffer[1024];
    while (true)
    {
        ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0); // recv的作用和read是一样的！recv是专门用于流式读取！
        if (n > 0)
        {
            buffer[n] = 0; // 加上\0当做字符串！
            inbuffer += buffer;
            // 进行分析处理——边读取边分析！
            auto pos = inbuffer.find(LINE_SEP);
            if (pos == std::string::npos)
                continue;
            // 没有找到说明连一个合法的请求都没有读取到！
            // 因为是字节流有可能 content_len\r\x op y\r\n这个完整的请求！
            // 只有content_len的这个扔了过来！所以我们就让其继续去读取！

            // 到这里我们一定能拿到长度！
            std::string text_len_string = inbuffer.substr(0, pos); // 无论如何都从重新开始
            int text_len = std::stoi(text_len_string);             // 正文的长度

            // 万一传过来的是这种情况要怎么办呢？content_len\r\x op y正文不全！
            // 我们如何知道是完整的呢？
            // text_len_string + "\r\n" + text + "\r\n" <=inbuffer.size()
            // 我们就能把握至少有一个完整的报文！
            int total_len = text_len_string.size() + 2 * LINE_SEP_LEN + text_len;
            if (inbuffer.size() < total_len)
                continue; // 那么就继续重新读取！

            std::cout << "处理前inbuffer :\n" << inbuffer << std::endl;
            // 到这里至少有一个完整的报文了！
            *text = inbuffer.substr(0, total_len);
            inbuffer.erase(0, total_len); // 去掉这个报文！

            std::cout << "处理后inbuffer :\n" << inbuffer << std::endl;

            break;
        }
        else // n == 0就是说明写端关闭！
        {
            return false;
        }

    }
    return true;
}
// 我们可以一次性读取多个报文！然后保存在数组里面！
// bool recvRequestAll(int sock ,std::vector<std::string>* out)
// {
//     std::string line;
//     while(recvRequest(sock,&line)) out->push_back(line);
    
// }